package com.neuronbit.businessflow.runtime.exec;

import com.neuronbit.businessflow.runtime.Flow;
import com.neuronbit.businessflow.runtime.FlowContext;
import com.neuronbit.businessflow.runtime.GsonUtil;
import com.neuronbit.businessflow.runtime.StepBeanProvider;
import com.neuronbit.businessflow.runtime.repo.BusinessFlowRepository;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.UUID;

public class BusinessFlow {
    private BusinessFlowRepository repository;
    private final StepBeanProvider stepBeanProvider;

    public BusinessFlow(BusinessFlowRepository repository, StepBeanProvider stepBeanProvider) {
        this.repository = repository;
        this.stepBeanProvider = stepBeanProvider;

        if (this.repository == null) {
            throw new IllegalStateException("No business flow repository found");
        }
    }

    public @Nullable ExecutedFlowInstance reRun(Class<?> flowType, String id) throws Exception {
        ExecutedFlowInstance instance = this.repository.findExecutedFlowInstance(flowType.getName(), id);
        if (instance == null) {
            throw new IllegalStateException("No executed flow instance found for flow type " + flowType.getName());
        } else {
            String flowTypeName = instance.getFlowTypeName();
            Class<?> flowClazz = Class.forName(flowTypeName);
            Object flowInstance = flowClazz.getConstructor(StepBeanProvider.class, String.class)
                    .newInstance(stepBeanProvider, UUID.randomUUID().toString());

            String className = instance.getContextTypeName();

            Object context = GsonUtil.fromJson(instance.getContext(), Class.forName(className));
            if (context != null) {
                ((Flow)flowInstance).reRun((FlowContext) context, false);
            } else {
                throw new IllegalStateException("No context found for flow type " + flowTypeName);
            }

            return instance;
        }
    }

}
